package com.app.Tree;
import java.io.File;
import java.util.ArrayList;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;



import ReadWriteXML.DOMUltil;
import ReadWriteXML.ReadXML;
import ReadWriteXML.WriteXML;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.RectF;
import android.graphics.Paint.Style;
import android.util.Log;

public class TreeNode extends INode {
	
	ArrayList<INode> nodes = new ArrayList<INode>();

	public TreeNode() {
		super();
		//this.expand=new CirleButton(this.x+this.width+CirleButton.r+CirleButton.space, this.y+this.heigh/2);
		this.generateSize();
		
	}
	public TreeNode(long id, String title, String text, float x, float y,String user, long vs, int lb, long pID) {
		super(id, title, text, x, y, user,vs,lb,pID);		
	//	this.expand=new CirleButton(this.x+this.width+CirleButton.r+CirleButton.space, this.y+this.heigh/2);
		this.generateSize();
	}

	@Override
	public void add(INode node) {
		node.setDepth(this.depth + 1);
		nodes.add(node);
	}

	@Override
	public void remove(INode node) {
		if(node==null)
			return;
		for (INode i : nodes) {
			i.remove(node);
		}
		
		nodes.remove(node);
		Log.d("An","Đã xóa node id="+node.getId());
	}

	@Override
	public void onDraw(Canvas canvas) {
		if (!showed)
			return;
		int space = 1;
		RectF border = new RectF(x - space, y - space, x + width + space, y
				+ heigh + space);

		Paint p1 = new Paint();
		p1.setAntiAlias(true);
		p1.setStrokeWidth(1);

		p1.setARGB(10, 10, 10, 10);

		RectF rect = new RectF(x, y, x + width, y + heigh);
		canvas.drawRoundRect(rect, 5, 5, p1);

		p1.setColor(Color.BLACK);
		String s = this.user + ": " + this.title;

		if (s.length() > 30)
			s = s.substring(0, 30) + "[...]";
		canvas.drawText(s, this.x, this.y + this.heigh - space, p1);

		// Vẽ border
		Paint p = new Paint();
		p.setStrokeWidth(1);
		p.setStyle(Paint.Style.STROKE);
		p.setAntiAlias(true);
		p.setColor(Color.rgb(56, 93, 138));
		canvas.drawRoundRect(border, 5, 5, p);

		//
		// Vễ đường nối và các node con
		Paint paint = new Paint();
		paint.setAntiAlias(true);
		paint.setStyle(Style.STROKE);
		paint.setStrokeWidth(1);
		paint.setColor(Color.RED);
		if (this.nodes.size() > 0) {
			expand.onDraw(canvas, paint);
		}
		if (expand.isExpand() && this.nodes != null && this.nodes.size() > 0) {

			Path path;
			for (INode node : nodes) {
				if (node.showed) {
					path = createPath(this, node);
					canvas.drawPath(path, paint);
					node.onDraw(canvas);

				}
			}			
		}
		// Vẽ note icon
		if (this.text != null && this.text.length() > 0) {
			RectF dst = new RectF(this.x + this.width - this.heigh, this.y,
					this.x + this.width, this.y + this.heigh);
			canvas.drawBitmap(bitmap, null, dst, paint);
		}
	}

	private Path createPath(INode node1, INode node2) {
		PointF p1, p2;
		p1 = new PointF(node1.x + node1.width+node1.expand.getR()*2, node1.y + node1.heigh / 2);
		p2 = new PointF(node2.x, node2.y + node2.heigh / 2);
		Path rs = new Path();
		float dx, dy, delta;
		dx = p2.x - p1.x;
		dy = p2.y - p1.y;

		dx = p2.x - p1.x;
		dy = p2.y - p1.y;
		delta = 10;
		rs.moveTo(p1.x, p1.y);
		rs.cubicTo(p1.x + delta, p1.y, p1.x + delta, p2.y, p2.x, p2.y);
		return rs;
	}

	@Override
	public INode getById(long id) {
		INode rs = null;
		if (this.id == id)
			rs = this;
		else {
			for (INode node : nodes) {
				rs = node.getById(id);
				if (rs != null)
					return rs;
			}
		}
		return rs;
	}

	@Override
	public ArrayList<INode> getChildren() {
		return nodes;
	}

	public INode getCollision(float x, float y) {
		INode rs = null;
		if(!this.showed)
			return rs;
		
		if (this.isCollision(x, y,15))
			return this;
		
		for (INode node : nodes) {
			rs = node.getCollision(x, y);
			if (rs != null)
				return rs;
		}
		return rs;
	}
	public INode getExpandCollision(float x,float y){
		INode rs = null;
		if(this.expand==null)
			return rs;
		if (this.expand.isCollision(x, y))
			return this;
		for (INode node : nodes) {
			rs = node.getExpandCollision(x, y);
			if (rs != null)
				return rs;
		}
		return rs;
	}
	public void setPostion(float x, float y) {
		super.setPostion(x, y);
	}

	public void moveAll(float moveX, float moveY) {
		super.setPostion(this.x + moveX, this.y + moveY);
		for (INode node : nodes) {
			node.moveAll(moveX, moveY);// (node.x+moveX, node.y+moveY);
		}
	}
	
	public void autoArrange() {
		float spaceX = 30;
		float spaceY = 10;
		int size = this.nodes.size();
		int leafCount, temp, leaf1, leaf2;
		INode cl = null;
		if (size == 0)
			return;
		if (size == 1) {
			nodes.get(0).setPostion(this.x + this.width + spaceX+CirleButton.space, this.y);
			nodes.get(0).autoArrange();
		} else {
			for (int i = 0; i < size; i++) {
				if (i == 0) {
					leafCount = this.countLeaf();
					//leafCount /= 2;
					//leafCount++;
					if (leafCount <= 0)
						leafCount = 1;
					nodes.get(i).setPostion(this.x + this.width + spaceX+CirleButton.space, this.y - this.heigh * leafCount);

				} else {
					leaf1 = nodes.get(i - 1).countLeaf();
					leaf2 = nodes.get(i).countLeaf();
					leafCount = leaf1 + leaf2;
					if (leafCount <= 2)
						leafCount = 1;
//					else
//						leafCount--;
					nodes.get(i).setPostion(this.x + this.width + spaceX+CirleButton.space, nodes.get(i - 1).y + leafCount * (this.heigh)+ this.heigh);
				}
				nodes.get(i).autoArrange();				
			}
		}
	}

	@Override
	public int getSumChildren() {
		int rs = this.nodes.size();
		for (INode node : this.nodes) {
			rs += node.getSumChildren();
		}
		return rs;
	}

	@Override
	public int getNodeHeight() {
		int rs = 0;
		if (this.nodes.size() > 0)
			rs++;
		return 0;
	}

	@Override
	public Element toXmlText(Document doc) {
		Element e = doc.createElement("TreeNode");
		e.setAttribute("ID", this.id + "");
		e.setAttribute("title", this.title);
		e.setAttribute("text", this.text + "");
		e.setAttribute("x", this.x + "");
		e.setAttribute("y", this.y + "");
		e.setAttribute("user", this.user);
		e.setAttribute("version", this.version + "");
		e.setAttribute("label", this.label + "");
		e.setAttribute("parentID", this.parentID+"");
		for (INode node : this.nodes) {
			e.appendChild(node.toXmlText(doc));
		}
		return e;
	}

	public void writeXML(String path) {
		Log.d("file","TreeNode - Đã ghi node xuong file:");
		File f = new File(path);
		if (f.exists())
			f.delete();
		Document doc = null;		
		doc = WriteXML.insertRoot(doc, path, "Root");
		doc.getFirstChild().appendChild(this.toXmlText(doc));
		DOMUltil.writeXmlToFile(path, doc);

	}
	
	public void writeDeletedXML(String path, long id, long vs) {
		File f = new File(path);
		if (f.exists())
			f.delete();
		Document doc = null;		
		doc = WriteXML.insertRoot(doc, path, "Delete");
		doc.getFirstChild().appendChild(this.toXmlDelete(doc, id, vs));
		DOMUltil.writeXmlToFile(path, doc);

	}
	
	@Override
	public Element toXmlDelete(Document doc, long id, long vs) {
		Element e = doc.createElement("DeletedNode");
		e.setAttribute("ID", id + "");
		e.setAttribute("version", vs + "");
		return e;
	}

	@Override
	public INode readXML(Element element) {
		
		this.id = Long.parseLong(element.getAttribute("ID"));
		this.title = element.getAttribute("title");
		this.setText(element.getAttribute("text"));
		this.x = Float.parseFloat(element.getAttribute("x"));
		this.y = Float.parseFloat(element.getAttribute("y"));
		this.user = element.getAttribute("user");
		this.version = Long.parseLong(element.getAttribute("version"));
		this.label = Integer.parseInt(element.getAttribute("label"));
		this.parentID = Long.parseLong(element.getAttribute("parentID"));
		this.generateSize();
		NodeList nodeList = element.getChildNodes();
		for (int i = 0; i < nodeList.getLength(); i++) {
			TreeNode n = new TreeNode();
			this.add(n.readXML((Element) nodeList.item(i)));
		}
		return this;
	}

	public boolean clearChildren() {
		for (INode node : this.nodes) {
			node.clearChildren();
			this.remove(node);
		}
		return true;
	}

	@Override
	public void zoomIn() {
		if (isZoomIn) {
			isZoomIn = false;
			this.heigh /= 2;
			this.width /= 2;

			for (INode node : nodes) {
				node.zoomIn();
				node.x -= node.width / 2;
				node.y -= node.heigh / 2;
			}
		} else {
			isZoomIn = true;
			this.heigh *= 2;
			this.width *= 2;

			for (INode node : nodes) {
				node.zoomIn();
				node.x += node.width / 2;
				node.y += node.heigh / 2;
			}
		}
	}
	public void readXml(String path) {
        Document doc = ReadXML.BuildXML(path);          
        this.readXML((Element) doc.getFirstChild().getFirstChild());
}

@Override
	public boolean haveOtherChildren(String myUserName) {
		boolean rs=false;
		if(!this.user.equals(myUserName))
			return true;
		for(INode node:nodes){
			rs=node.haveOtherChildren(myUserName);
			if(rs==true)
				break;
		}
		return rs;
	}
	@Override
	public int countLeaf() {
		int rs = 0;
		if (this.expand.isExpand()) {
			for (INode node : nodes) {
				if (node.getChildren().size() == 0)
					rs++;
				else {
					rs += node.countLeaf();
				}
			}
		}else{
			rs++;
		}
		return rs;
	}

	@Override
	public void expand(boolean expand) {
		this.expand.setExpand(expand);
		this.showChildren(expand);
		
		for(INode node:nodes){
			node.expand(expand);			
		}
	}

	@Override
	public void showChildren(boolean show) {
		for(INode node:nodes){
			node.showed=show;
			node.showChildren(show);
		}
	}
	@Override
	public void autoArrangeTextNode() {
		// TODO Auto-generated method stub
		
	}
	
	@Override
	public String GetStringNode(long vs){
		Log.d("An", "TreeNode-GetStringNode....: ");
		String s = "";
		if  (this.version  > vs){			
			s += this.toParse() + "/";
			Log.d("An", "TreeNode-GetStringNode....s1 = : "+s);
		}
		if(this.nodes.size()<=0){
			Log.d("An", "TreeNode-GetStringNode.... this.nodes.size()<=0 : "+s);
			return s;
		}
		for  (INode node : nodes) {
			if  (node.version  > vs) {
				s += node.GetStringNode(vs);
				Log.d("An", "TreeNode-GetStringNode....s2 = : "+s);
			}
		}		
		return s;
	}
	@Override
	public void generateSize(){
		super.generateSize();
		this.expand=new CirleButton(this.x+this.width+CirleButton.r, this.y+this.heigh/2);		
		this.loadResources();
	}
	public void copy(INode node){
		super.copy(node);
		this.generateSize();
	}

	public  String readDelXML(String path) {
		String s = "";
		String add = "";
		Document doc = ReadXML.BuildXML(path);
//		Log.d("An", "TreeNode-readDelXML- Document: " + (doc==null) );
		if (doc != null) {
			NodeList delNode = doc.getElementsByTagName("DeletedNode");
			int n = delNode.getLength();
			if(n!= 0){
				for(int i=0; i<n; i++){
					Element e = (Element)delNode.item(i);
					add = e.getAttribute("ID") +"/"+ e.getAttribute("version");
					s += add+"#";
				}
			}
		}
//		Log.d("An", "TreeNode-readDelXML- s= " + s );
		return s;
	}
	
	public void deleteNode(long id, long version){
		for(INode node : nodes){
			if(node.getId() == id){
//				Log.d("An", "GetStringNode- ID: " +node.getId() +" = "+id);
				remove(node);
			}
		}
	}
	

}
